package com.imooc.Aspect;

import com.imooc.vo.EnRespStatus;
import com.imooc.vo.RspBaseVO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import javax.validation.Valid;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Title JSR303数据校验切面
 * @Description 当校验不通过时，自动处理校验结果，停止当前请求，并响应错误提示
 * @author zc
 * @version 1.0 2017-11-08
 */
@Aspect
@Component
public class ValidAdvisor {

// 通过@Pointcut注解声明切点。
    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void annotationPointCut() {
    };

    @Around("annotationPointCut()")
    public Object doTest(ProceedingJoinPoint pjp) throws Throwable{
        
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        
        @SuppressWarnings("rawtypes")
        Class retuenClazz = signature.getReturnType();
        Object retuenObject = retuenClazz.newInstance();
        
        if(!(retuenObject instanceof RspBaseVO)){
            throw new RuntimeException("方法"+method.getName()+"返回值类型非法");
        }
        
        RspBaseVO rspVO = (RspBaseVO)retuenObject;
        
        Object[] args = pjp.getArgs();
        
        Annotation[][] annotations = method.getParameterAnnotations();
        for(int i = 0; i < annotations.length; i++){  
            if(!hasValidAnnotation(annotations[i])){  
                continue;  
            }  
            if(!(i < annotations.length-1 && args[i+1] instanceof BindingResult)){
                //验证对象后面没有跟bindingResult,事实上如果没有应该到不了这一步  
                continue; 
            }
            BindingResult result = (BindingResult) args[i+1];  
            if(result.hasErrors()){
                FieldError fieldError = result.getFieldError();
                rspVO.setEnRespStatus(EnRespStatus.PARAM_INVALID);
                rspVO.setRespDesc(fieldError.getField() + fieldError.getDefaultMessage());
                return rspVO;  
            }
        }
        return pjp.proceed();
    }
    
    /**
     * 校验是否有@Valid注解
     */
    private boolean hasValidAnnotation(Annotation[] annotations){  
        if(annotations == null){  
            return false;  
        }  
        for(Annotation annotation : annotations){  
            if(annotation instanceof Valid){
                return true;  
            }  
        }  
        return false;  
    }
    
}